最近一段时间一直在学习CNN在NLP方面的应用,主要是学习如何利用CNN解决NLP的传统任务,如文本分类、句子相似度计算等。在此期间阅读了一些论文和博客,在此系统整理一下,以便加强理解。
CNN简介
卷积神经网络(Convolutional Neural Network, CNN或ConvNet)是一种具有局部连接、权重共享等特性的前馈神经网络。经典的CNN的架构LeNet-5如下图所示:
整个网络由卷积层、池化层以及全连接层等组成。下面简要介绍不同层的操作及作用。
卷积层
卷积,是一种重要的数学运算, 在信号处理或图像处理中,经常使用一维或二维卷积。一维卷积常用在信号处理中,用于计算信号的延迟累积。在图像处理中经常使用的是二维卷积,以图像作为输入,比较容易理解卷积的方法就是把卷积想象成作用于矩阵的一个滑动窗口函数。如下图所示:
滑动窗口矩阵称为卷积核(convolution kernel)或滤波器(filter)。在上图中,使用33的卷积核与矩阵对应的部元素相乘,然后相加。然后,按照一定的步长从上到下,从左到右不断执行卷积操作,就会得到如右边所示的输出矩阵。*在图像处理中,卷积经常作为特征提取的有效方法。
卷积操作是一种局部操作,其作用是提取一个局部区域的特征,一个卷积层可以设置多个卷积核,可以提取不同的特征。卷积核参数可以通过网络训练学习出来。除了可以学到类似横向、纵向边缘滤波器,还可以学到任意角度的边缘滤波器。通过组合这些滤波器以及后续的操作进行,基本而一般的模式会逐渐被抽象为具有高层语义的概念表示,并以此对应到样本类别。和盲人摸象类似,首先摸到比较粗的腿、长长的鼻子、大大的耳朵等局部区域特征,然后将这些特征组合在一起,判断是像。而卷积在此处的作用就是摸的过程中提取腿、鼻子、耳朵等局部区域特征。
池化层(pooling)
卷积神经网络中的另一个重要的概念就是池化层,一般卷积层之后都会接一个池化层。池化层对输入数据做降采样操作。例如,下图就是2*2窗口的max-pooling,及其输出结果:
池化操作也可以看成是一个p-范数作为非线性映射的“卷积”操作,特别当趋近于正无穷时,就是常见的max pooling。常见的池化操作有如下几种:
- Max-pooling:最大池化,取整个区域内的最大值作为特征,在自然语言处理中,常用于分类问题,希望观察到特征是强特征,以便可以区分哪一个类别。
- Averge-pooling:平局池化。取整个区域内的均值作为特征。常用于主题模型,一个句子可能不止一个主题标签,如果使用Max-pooling的话只保留最强的特征,获取信息较少,使用Average可以广泛反映这个区域的特征;
- K-max pooling:k-最大池化,选取整个区域内前k个最大的特征。
pooling操作具有如下作用:
- 特征不变性,pooling操作使模型更关注是否存在某些特征,而不是特征的具体位置。可以看做是一种很强的先验,使特征学习包含某种程度自由度,能容忍一些特征微小的位移,使得网络的鲁棒性增强,有一定的抗干扰的作用;
- 特征降维,由于pooling操作为降采样操作,因此相当于在空间范围内做降维操作,从而使模型可以抽取更广泛的特征。同时,减小了下一层的输入大小,进而减小计算量和参数的个数;
- 在一定程度上防止过拟合,更方便优化。
关于CNN的更多详细内容,可以参考[1]《解析卷积神经网络—深度学习实践手册》。
CNN 在NLP应用上的一些论文
TextCNN[2]
在图像处理中卷积核通过对图像的一小块区域进行卷积操作。但是,文本与图像不同,一个句子构成的词向量作为输入。每一行代表一个词的词向量,在处理文本时,卷积核通常覆盖上下几行的词,此时卷积核的宽度与输入数据的宽度相同,通过这样的方式,能够捕捉到多个连续词之间的特征,并且能够在同一类特征计算时中共享权重。Kim Y’s 论文讲的是如何利用CNN做文本分类,论文中的模型结构如下图所示:
如上图所示,句子长度为9,embeding大小为6。卷积核的宽度为6,和词embeding的大小相同,滑动窗口的大小为2和3。使用卷积核进行卷积,在第一层学到的卷积核捕捉的特征与n-gram非常相似,(但不局限于),但是以更紧凑的方式表征。
通过卷积操作,每个卷积核都可以提取出响应的Feature Map,不同的句子长度,产生的Feature Map的行数不同。但是,在池化层,采样Max Pooling,可以将每个Feature Map的维度全部降为1。所以,pooling之后,得到的向量维度,就是卷积层Feature Map的数量。因此,解决了不同文本长度不统一的问题。
- 输入层
如上图所示,输入层是句子中词语对应的向量表示形式,从上到下表示。假设句子有n个词,词向量的维度是k,则输入矩阵为n*k。输入矩阵的类型分为静态和动态两种形式,静态表示在训练过程中固定不变,动态表示模型训练过程中,词向量也当做是可优化的参数。通常把反向传播导致词向量中值发生变化的这一过程称为Fine tune。对于未登录词,用0或者随机小的正数填充。
- 卷积层
输入层经过卷积操作得到若干Feature Map,卷积窗口大小为h*k,h表示滑动窗口大小,k表示词向量大小;通过这样一个卷积核,将得到若干个列数为1的Feature Map。
- 池化层
池化层采用的是max-pooling,这种pooling方式可以解决可变长度句子输入问题。最终池化层的输出为各个Feature Map的最大值,即一个一维向量。
- 全连接+Softmax层
池化层的一维向量的输出通过全连接的方式,连接一个Softmax层,Softmax层可根据任务的需要设置。最终实现时,可以在倒数第二层的全连接部分上使用Dropout技术,以及L2正则化防止过拟合。
一些结论:
- CNN-static比CNN-rand好,说明预训练的词向量确实有较大的提升作用;
- CNN-non-static比大部分的CNN-static好,说明适当的Fine tune也是有利的,使得词向量更加贴近于具体的任务;
- CNN-multi channel较与CNN-single在小规模的数据集上有更好的表现,实际上CNN-multichannel体现了一种折中思想,即,既不希望Fine tuned的词向量距离原始值太远,但同时保留一定的变化空间。
DCNN[3]
这篇论文提出了一种DCNN(Dynamic Convolutional Neural Network)的模型,该模型提出了动态Pooling的方法。
论文中首先对句子语义建模,在底层通过组合临近的词语信息,逐步向上传递,上层则又组合新的语义信息,从而使得句子中相离较远的词语也有交互的行为。从直观上看,这个模型能够通过词语的组合,再通过池化层提取出句子中重要的语义信息。
该模型的架构如下图所示:
网络架构中的卷积层使用的是宽卷积(Wide Convolutional)的方式,紧接着是动态k-max pooling。中间卷积层的输出即Feature Map的大小会根据输入句子的长度而变化。
首先从卷积层看,卷积层采用的是宽卷积,句子长度为7,词向量维度为5,宽卷积窗口大小为3。经过卷积操作之后,为pooling操作,这里pooling采用的是k-max pooling。
k-max pooling的好处在于,既能提取出来句子的较为重要的信息,同时保留了它们的次序信息(相对位置)。同时,由于应用在最后的卷积层上只需要提取出k个值,所以这种方法允许不同长度的输入。然而,对于中间的卷积层而言,参数k也不是固定的。k的计算公式如下:
其中,l表示当前卷积的层数,L为网络中总共卷积的层数,$k_top$为最顶层卷积层pooling的k值,是一个固定的值。
经过pooling操作之后,从在一个Folding操作,这个操作是吧pooling的输出结果相邻的两行相加。这种操作则是考虑相邻两行之间的某种联系。最后,在经过一个k-max pooling操作,进行全连接操作。
该模型具有如下特点:
- 保留了句子中词序信息和词语之间的相对位置;
- 宽卷积的结果是传统卷积的一个扩展,某种意义上,也是n-gram的一个扩展;
- 模型不需要任何的先验知识,例如句法依存树等,并且模型考虑了句子中相隔较远的词语之间的语义信息。
RCNN[4]
这篇论文首先介绍了传统的文本分类任务,并比较了一些常用方法的优缺点。首先是介绍文本分类任务。首先介绍文本的表示方法,传统的方法如Bag of words,比如n-gram、pattern等。用词频、MI、pLSA、LDA作为特征选择的方法。传统的特征表达方法经常忽略上下文的信息和词序信息,以及语义信息;高阶的n-gram、tree kernels也可以应用在特征表达,但是也存在稀疏的缺点,影响准确性。
Recursive Neural Network:
效果完全依赖于文本树的构建,并且构建文本树需要的时间为$O(n^2)$。同时,两个句子的关系也不能通过一颗树表现出来。因此,不适合长句子或长文本建模。
Recurrent Neural Network:
循环神经网络能够保留一个句子的上下文信息。但是,其是一个有偏的模型,后面的词占得重要性更大。因此,如果用它来捕捉整个文档的语义,其效果可能不太好。因为,整个文档关键的部分可能分布在文档的各个部位,而不仅仅是文档的末尾。
Computational Neural Network:
CNN是一个无偏的模型,能够通过最大池化获得最重要的特征。它的缺点是卷积核大小是固定的,如果卷积核选小了容易造成信息的丢失;如果选大了,参数空间会变得很大。
针对上面不同模型存在的缺陷,论文提出Recurrent Convolutional Neural Network (RCNN)。模型采用双向循环结构:相比传统的基于窗口的神经网络噪声要更小,能够最大化提取上下文信息。模型采用max-pooling自动决策哪个特征有更加重要的作用。模型的架构如下图所示:
首先,定义一些符号:
- $c_l(w_i)$:表示词$w_i$左边的上下文表示;
- $c_r(w_i)$:表示词$w_i$右边的上下文表示;
- $e(w_i)$:表示词$w_i$的词向量表示;
$c_l(w_i)$和$c_r(w_i)$可以通过下面的公式计算:
$$
c_l(w_i) = f(W^{(l)}c_l(w_{i-1})+W^{(sl)}e(w_{i-1})) \\
c_r(w_i) = f(W^{(r)}c_r(w_{i+1})+W^{(sr)}e(w_{i+1}))
$$
其中,$W^{(l)}$、$W^{(r)}$、$W^{(sl)}$、$W^{(sr)}$为相应的参数矩阵,全局共享相同的参数。
$c_l(w_i)$和$c_r(w_i)$计算完成之后,词i可以用下面的公式表示:
$$x_i =[c_l(w_i);e(w_i);c_r(w_i)]$$
得到词i的表示$x_i$之后,经过线性变换,加tanh激活函数,输出到下一层:
$$y_i^{(2)} = tanh(W^{(2)}x_i+b^{(2)})$$
其中,$y_i^{(2)}$是一个latent semantic向量,用来分析计算最有用的文本表示。
到目前为止,第2层的操作已经完成。接下来是max-pooling层,其操作如下:
$$y^{(3)} = max_{i=1}^n y_i^{(2)}$$
max操作是一个element-wise的函数。$y^{(3)}$的第k个元素,是$y_i^{(2)}$第k列最大的元素。
max-pooling操作后,输出层就是传统的全连接+Softmax操作。
分段pooling[5]
这篇提出了一个分段pooling的操作解决关系抽取问题。关系抽取问题可以简单的理解分析一段文本中两个实体之间的关系。一般可以将关系抽取问题转化为分类问题(个人理解)。
比如,下面的一句话,涉及两个实体,实体之间的关系
The [fire] inside WTC was caused by exploding [fuel].
关系: Cause-Effect
论文中提出的模型如下所示:
首先,卷积操作,和之前介绍的卷积操作相同,但是,模型中的卷积,将文本分为3部分,每一部分分别进行卷积,和池化。对于上图中的示例,句子中涉及到两个实体,Kojo Annan和Kofi Annan,以这两个实体为分界线可以将句子分为3部分:
- […,hired, Kojo Annan]
- [,the,son,of]
- [Kofi Annan,in,…]
模型对这三部分分别进行卷积,每部分卷积后的输出,再分别进行pooling操作,具体操作可以简单表示为如下。
如图中所示,在pooling阶段,$max(c_{11})$、$max(c_{12})$、和$max(c_{13})$表示第一个Feature Map的分段pooling的结果,图中存在3个Feature Map。同时,模型中也加入了对位置的embedding,具体可以参考论文。
CNN参数如何调
论文[6]中提供了一些CNN相关调参策略。相关的终结如下:
使用什么样的词向量?
- 使用预训练的词向量比随机初始化的效果要好;
- 采取微调策略(non-static)的效果比固定词向量(static)的效果要好;
- 如果无法确定用哪种预训练词向量(word2vec/Glove等)更好,不同的任务结果不同,应该针对当前的任务进行试验。
Filter窗口大小和数量设置
- 每次使用一种类型的Filter进行试验,表明Filter的窗口大小设置在1到10之间是一个比较合理的选择;
- 首先,在一种类型的Filter大小上搜索,以找到当前数据集的“最佳”大小,然后探索这个最佳大小附近的多种Filter大小的组合;
- 每种窗口类型的Filter对应的“最好”的Filter个数(feature map数量)取决于具体数据集;
- 通过可以看出,当Feature Map数量超过600时,performance提高有限,甚至会损害performance。这可能是过多的feature Map数量导致过拟合;
- 在实践中,100到600是一个比较合理的搜索空间;
激活函数选择
- Sigmoid,Cube,Tanh Cube相较于Relu和Tanh,表现很糟糕;
- Tanh比Sigmoid好,这可能是由于Tanh具有zero-centering性质;
- 与Sigmoid相比,ReLU具有非饱和形式(a-non-saturating form)的优点,并能够加速SGD的收敛;
- 对于某些数据集,线性变换(Iden,即不使用非线性激活函数)足够捕获词嵌入与输出标签之间的相关性。(但是如果有多个隐藏层,相较于非线性激活函数,Iden就不太合适了,因为完全用线性激活函数,即使有多个隐藏层,组合后整个模型还是线性的,表达能力可能不足,无法捕获足够信息);
- 因此,建议首先考虑ReLU和Tanh,也可以尝试Iden;
Pooling的选择
- 对于句子分类任务,max-pooling往往比其他池化策略要好。这可能是因为上下文的具体位置对于预测Label可能并不是很重要,而句子某个具体的n-gram(1-max pooling后Filter提取出的特征)可能更可以刻画整个句子的某些含义,对于预测类别更有帮助;
- 但是在其他任务,如释义识别,k-max pooling可能更好;
正则化参数
- 0.1到0.5之间的非零dropout rates能够提高一些performance(尽管提升幅度很小),具体的最佳设置取决于具体数据集;
- 对于l2 norm加上一个约束往往不会提高performance;
- 当Feature Map的数量大于100时,可能会导致过拟合,影响performance,而dropout将减轻这些影响;
- 在卷积层上进行dropout帮助很小,而且较大dropout rate对performance有坏的影响;
总结
目前,对CNN在NLP相关任务上的应用已经有了一个基本的了解。CNN能够捕捉到局部的特征,在自然语言处理中能够起到n-gram的作用,通过将捕捉到的局部特征进行组合,组合的结果可以看成是对输入文本的文本表示,在这个文本表示的基础之上可以完成各种NLP任务。整体的框架和其在图像方面的应用相差不大。但是,有时需要针对特定的任务对模型进行一定程度的修改,比如卷积层的输入,除了词的向量组成的矩阵之外、还可以加入位置的embeding以及采用non-static和static的向量组成多通道。在pooling层可以选择max-pooling、k-max pooling以及动态k-max pooling等多种类型的pooling操作。
参考
- 《解析卷积神经网络—深度学习实践手册》
- Kim Y. Convolutional neural networks for sentence classification[J]. arXiv preprint arXiv:1408.5882, 2014.
- Kalchbrenner N, Grefenstette E, Blunsom P. A convolutional neural network for modelling sentences[J]. arXiv preprint arXiv:1404.2188, 2014.
- Recurrent Convolutional Neural Network for Text Classification, Siwei Lai etc.
- Distant Supervision for Relation Extraction via Piecewise Convolutional Neural Networks. Daojian Zeng, Kang Liu, Yubo Chen and Jun Zhao.
- Zhang Y, Wallace B. A Sensitivity Analysis of (and Practitioners’ Guide to) Convolutional Neural Networks for Sentence Classification[J]. arXiv preprint arXiv:1510.03820, 2015.